#!/usr/bin/env python

import re
import xlwt
import component
import messaging.sms

from autorm.fields import *

from _outbox import Outbox
from _contact import Contact

class Message(component.Model):
    '''Message class
    
    @author Julot <andy.julot@gmail.com>
    @since Wednesday, February 15, 2012. 03:47 PM'''
    
    LABEL_INBOX = 'inbox'
    LABEL_TRASH = 'trash'
    LABEL_ARCHIVE = 'archive'
    LABEL_OUTBOX = 'outbox'
    LABEL_SENT = 'sent'
    
    class Meta:
        table = 'messages'
        pk = 'id'
        fields = [IdField('id'),
                  ISODateTimeField('insertTime'),
                  ISODateTimeField('updateTime'),
                  ISODateTimeField('dateTime', index=True),
                  ISODateTimeField('deleteTime'),
                  BoolField('seen', index=True, default=False),
                  IntegerField('total', index=True),
                  IntegerField('sequence'),
                  IntegerField('reference'),
                  CsvField('labels', collate='NOCASE'),
                  CsvField('numbers'),
                  TextField('message'),
                  TextField('pdu')]
    
    @property
    def completeMessage(self):
        if self.total == 1: return self.message
        
        timedelta = datetime.timedelta(minutes=10)
        query = self.objects.query(reference=self.reference, sequence__gt=1,
                                  dateTime__gte=self.dateTime - timedelta)
        query.order_by('sequence')
        sequence = 1
        message = self.message
        for q in query:
            sequence += 1
            if q.sequence != sequence:
                message += "\r\n...\r\n"
            else:
                message += q.message
        if sequence < self.total:
            message += "\r\n..."
        return message
    
    @classmethod
    def toExcel(cls, path):
        wb = xlwt.Workbook()
        ws = wb.add_sheet('SMS')
        ws.write(0, 0, 'No')
        ws.write(0, 1, 'Time')
        ws.write(0, 2, 'Number')
        ws.write(0, 3, 'Message')
        
        query = cls.objects.query().order_by('dateTime', 'desc')
        query.filter(labels__regexp=r'\b%s\b' % cls.LABEL_INBOX, sequence__lt=2)
        
        row = 0
        for q in query:
            row += 1
            ws.write(row, 0, row)
            date = q.dateTime.strftime('%Y-%m-%d %H:%M:%S')
            ws.write(row, 1, date)
            ws.write(row, 2, ', '.join(q.numbers))
            ws.write(row, 3, q.completeMessage)
            
        wb.save(path)
    
    def archive(self):
        labels = self.labels
        labels.append(self.LABEL_ARCHIVE)
        self.labels = labels
        self.save()
    
    def trash(self):
        labels = self.labels
        labels.append(self.LABEL_TRASH)
        self.labels = labels
        self.deleteTime = datetime.datetime.now()
        self.save()
    
    def recover(self):
        labels = self.labels
        try: labels.remove(self.LABEL_TRASH)
        except: pass
        self.labels = labels
        self.deleteTime = None
        self.save()
        
    def send(self):
        outboxes = []
        value = self.numbers
        destinations = [x.strip() for x in value.split(',')]
        numbers = []
        for destination in destinations:
            value = self.extractNumber(destination)
            if type(value) in (list, tuple):
                for each in value:
                    numbers.append(each)
            else:
                numbers.append(value)
        for number in set(numbers):
            try:
                messaging.sms.SmsSubmit(number, self.message)
            except:
                return False
            
            outbox = Outbox()
            outbox.number = number
            outbox.message = self.message
            outboxes.append(outbox)
        
        for outbox in outboxes: outbox.save()
        
        self.dateTime = datetime.datetime.now()
        self.seen = True
        self.total = 1
        self.sequence = 0
        self.reference = 0
        labels = self.labels
        labels.append(self.LABEL_SENT)
        self.labels = self.labels
        self.save()
        
        return True

    def extractNumber(self, value):
        # If integer, that that's it, return immediately.
        try:
            number = int(value)
            # Return the original value since we want to preserve the plus sign.
            return value
        except: pass
        
        # If not integer, then it maybe contact or group.
        # Check for contact first.
        number = re.sub(r".*<([\+0-9]+)>", r"\1", value)
        try:
            x = int(number)
            return number
        except: pass
        
        # The value is most likely a group.
        # Do it here.
        contacts = Contact.objects.query(groups__regexp=r'\b%s\b' % value)
        numbers = []
        for contact in contacts:
            for phone in contact.phones:
                numbers.append(phone)
        return numbers